#include "gic.h"
#include "key.h"

/* 描述：获取GIC控制器的基地址
 * 参数：无
 * 返回值：GIC控制器的基地址 */	
GIC_Type * get_gic_base(void)
{
	GIC_Type *dst;

	__asm volatile ("mrc p15, 4, %0, c15, c0, 0" : "=r" (dst)); 

	return dst;
}

/* 描述：GIC控制器初始化
 * 参数：无
 * 返回值：无 */	
void gic_init(void)
{
	u32 i, irq_num;

    /* 1、获取GIC控制器的基地址 */
	GIC_Type *gic = get_gic_base();

	/* 2、获取imxull的中断个数，注意: 中断个数 = irq_num * 32*/
	irq_num = (gic->D_TYPER & 0x1F) + 1;

	/* 3、禁止所有的PPI、SIG、SPI中断，每个ICENABLER寄存器对应32个中断号 */
	for (i = 0; i < irq_num; i++)
        gic->D_ICENABLER[i] = 0xFFFFFFFFUL;

	/* 4、把所有的中断都发给group0，每个IGROUPR寄存器对应32个中断号 */
	for (i = 0; i < irq_num; i++)
	  gic->D_IGROUPR[i] = 0x0UL;

	/* 5、所有的SPI中断都发给cpu interface 0，D_ITARGETSR定义为8位数据类型，只对应一个中断号 */
	for (i = 32; i < (irq_num * 32); i++)
	    gic->D_ITARGETSR[i] = 0x01UL;

	/* 6、设置所有的SPI中断触发类型，0-level, 1-edge  */
	for (i = 2; i < irq_num << 1; i++)
	    gic->D_ICFGR[i] = 0x01010101UL;

	/* 7、优先级过滤设置，允许imx6ull所有的32个优先级 */
	gic->C_PMR = (0xFFUL << (8 - 5)) & 0xFFUL;
	
	/* 8、设置优先级组，[7:3]五位都为抢占优先级，没有子优先级 */
	gic->C_BPR = 7 - 5;
	
	/* 9、使能group0给CPU interface分发中断 */
	gic->D_CTLR = 1UL;
	
	/* 10、使能CPU interface给processor分发中断 */
	gic->C_CTLR = 1UL;
}

/* 描述：使能中断号为nr的中断
 * 参数：中断ID
 * 返回值：无 */	
void gic_enable_irq(uint32_t nr)
{
	GIC_Type *gic = get_gic_base();

	/* The GICD_ISENABLERs provide a Set-enable bit for each interrupt supported by the GIC.
	 * Writing 1 to a Set-enable bit enables forwarding of the corresponding interrupt from the
	 * Distributor to the CPU interfaces. Reading a bit identifies whether the interrupt is enabled.
	 */
	gic->D_ISENABLER[nr >> 5] = (uint32_t)(1UL << (nr & 0x1FUL));

}

/* 描述：禁止中断号为nr的中断
 * 参数：中断ID
 * 返回值：无 */
void gic_disable_irq(uint32_t nr)
{
	GIC_Type *gic = get_gic_base();

	/* The GICD_ICENABLERs provide a Clear-enable bit for each interrupt supported by the
	 * GIC. Writing 1 to a Clear-enable bit disables forwarding of the corresponding interrupt from
     * the Distributor to the CPU interfaces. Reading a bit identifies whether the interrupt is enabled. 
	 */
	gic->D_ICENABLER[nr >> 5] = (uint32_t)(1UL << (nr & 0x1FUL));
}

/* 描述：获得当前中断的 interrtup ID。
 * 参数：无
 * 返回值：中断ID */
uint32_t get_gic_irq(void)
{
	uint32_t nr;

	GIC_Type *gic = get_gic_base();
	/* The processor reads GICC_IAR to obtain the interrupt ID of the
	 * signaled interrupt. This read acts as an acknowledge for the interrupt
	 */
	nr = gic->C_IAR;

	return nr;
}

/* 描述：清除中断，表示该中断已经处理完毕
 * 参数：中断ID
 * 返回值：无 */
void clear_gic_irq(int nr)
{

	GIC_Type *gic = get_gic_base();

	/* write GICC_EOIR inform the CPU interface that it has completed 
	 * the processing of the specified interrupt 
	 */
	gic->C_EOIR = nr;
}

/* 描述：IRQ中断处理函数
 * 参数：无
 * 返回值：无 */
void do_irq_c(void)
{
	int irq;
	
	/* 1. 分辨中断，获取当前中断号 */
	irq = get_gic_irq();

	/* 2. 调用处理函数 */
	if (irq == (67 + 32))
	{
        irq_hander_gpio1_16_32();
	}

	/* 3. 清除中断 */
	clear_gic_irq(irq);
}
